import java.io.IOException;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpRequest;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class HttpClientUtil {

    public static String doPost(String url, Map<String, String> headerMap, String body) {


        long start = System.currentTimeMillis();

        System.out.println("HttpClientUtil doPost url: " + url);
        if (headerMap != null && headerMap.keySet().size() > 0) {
            System.out.println("HttpClientUtil doPost header: " + headerMap);
        }

        // 构建请求体
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(setRequestConfig());

        // 构建请求头
        buildHeader(headerMap, httpPost);

        // 返回响应信息
        String result = null;

        try {
            // 设置请求参数
            StringEntity stringEntity = new StringEntity(body);
            stringEntity.setContentEncoding("UTF-8");
            stringEntity.setContentType("application/json"); // 发送 json 数据需要设置contentType
            httpPost.setEntity(stringEntity);

            CloseableHttpResponse response = httpClient.execute(httpPost);
            int resStatusCode = response.getStatusLine().getStatusCode();
            if (200 == resStatusCode) {
                result = EntityUtils.toString(response.getEntity());
                System.out.println("HttpClientUtil doPost response: " + result);
            } else if (401 == resStatusCode) {
            } else {
                String content = "HttpClientUtil post 请求失败。状态码：" + resStatusCode + "，url：" + url;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 请求用时
        long end = System.currentTimeMillis();
        System.out.println("HttpClientUtil doPost duration: " + (end - start) + " ms");

        return result;

    }

    public static String doGet(String url, Map<String, String> headerMap, Map<String, Object> paramMap) {


        long start = System.currentTimeMillis();

        // 构建请求地址
        url = buildUrl(url, paramMap);

        System.out.println("HttpClientUtil doGet url: " + url);
        if (headerMap != null && headerMap.keySet().size() > 0) {
            System.out.println("HttpClientUtil doGet header: " + headerMap);
        }

        // 连接池
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(100); // 最大连接数
        connectionManager.setDefaultMaxPerRoute(20); // 每个路由的最大连接数

        // 构建请求体
        CloseableHttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connectionManager).build();
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(setRequestConfig());

        // 构建请求头
        buildHeader(headerMap, httpGet);

        // 返回响应信息
        String result = null;
        CloseableHttpResponse response = null;

        try {
            response = httpClient.execute(httpGet);
            //
            int resStatusCode = response.getStatusLine().getStatusCode();
            if (200 == resStatusCode) {
                result = EntityUtils.toString(response.getEntity());
                System.out.println("HttpClientUtil doGet response: " + result);
            } else if (401 == resStatusCode) {
            } else {
                String content = "HttpClientUtil get 请求失败。状态码：" + resStatusCode + "，url：" + url;
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 读取响应内容，确保连接可以重用
                if (response != null) {
                    EntityUtils.consume(response.getEntity());
                    // 将连接释放回连接池
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 清理过期链接
            connectionManager.closeExpiredConnections();
        }

        // 请求用时
        long end = System.currentTimeMillis();
        System.out.println("HttpClientUtil doGet duration: " + (end - start) + " ms");

        return result;

    }

    public static String buildUrl(String url, Map<String, Object> paramMap) {

        StringBuilder sb = new StringBuilder(url);

        if (paramMap != null && paramMap.keySet().size() > 0) {
            // 问号
            sb.append("?");
            // 入参
            for (String key : paramMap.keySet()) {
                sb.append(key).append("=").append(paramMap.get(key)).append("&");
            }
            url = sb.toString();
            // 移除最后的 &
            if (paramMap.keySet().size() > 0) {
                url = url.substring(0, url.length() - 1);
            }
        }

        return url;
    }

    private static RequestConfig setRequestConfig() {
        return RequestConfig.custom() //
            .setConnectTimeout(20000) //
            .setConnectionRequestTimeout(20000) //
            .setSocketTimeout(20000) //
            .build() //
        ;
    }

    private static void buildHeader(Map<String, String> headerMap, HttpRequest httpRequest) {
        //        httpRequest.setHeader("Accept", "application/json");
        //        httpRequest.setHeader("Content-Type", "application/json; charset=UTF-8");
        if (headerMap != null) {
            for (String key : headerMap.keySet()) {
                httpRequest.setHeader(key, headerMap.get(key));
            }
        }
    }

    public static String getString(String res, String key) {
        JSONObject jsonObject = JSON.parseObject(res);
        String s = jsonObject.getString(key);
        //        s = toUnderlineJSONString(s);
        return s;
    }

    public static <T> List<T> getList(String res, String key, Class<T> t) {
        return buildList(res, key, t, false);
    }

    /**
     * 请求结果字段下划线分割, 转驼峰
     */
    public static <T> List<T> getCamelList(String res, String key, Class<T> t) {
        return buildList(res, key, t, true);
    }

    private static <T> List<T> buildList(String res, String key, Class<T> t, boolean buildCamel) {
        JSONObject jsonObject = JSON.parseObject(res);
        JSONArray jsonArray = jsonObject.getJSONArray(key);
        String s;
            s = JSON.toJSONString(jsonArray);
        return JSON.parseArray(s, t);
    }


}
